// GenerateOptionsDialog.java
package com.plugin.mybtaisxplus.dialog; // 包声明：定义对话框的子包路径

import com.intellij.openapi.fileChooser.FileChooser; // 导入：文件选择器
import com.intellij.openapi.fileChooser.FileChooserDescriptor; // 导入：文件选择器描述符
import com.intellij.openapi.project.Project; // 导入：项目接口
import com.intellij.openapi.ui.DialogWrapper; // 导入：对话框包装器基类
import com.intellij.openapi.ui.Messages; // 导入：消息对话框工具
import com.intellij.openapi.vfs.VirtualFile; // 导入：虚拟文件系统接口
import com.intellij.openapi.vfs.LocalFileSystem; // 导入：本地文件系统
import org.jetbrains.annotations.NotNull; // 导入：非空注解
import org.jetbrains.annotations.Nullable; // 导入：可空注解

import javax.swing.*; // 导入：Swing UI 组件包
import javax.swing.event.DocumentEvent; // 导入：文档事件
import javax.swing.event.DocumentListener; // 导入：文档监听器接口
import javax.swing.table.DefaultTableModel; // 导入：默认表格模型
import java.awt.*; // 导入：AWT 图形组件包
import java.util.ArrayList; // 导入：动态数组
import java.util.Arrays; // 导入：数组工具类
import java.util.List; // 导入：列表接口
import java.util.Objects; // 导入：Objects 工具类
import java.util.stream.Collectors; // 导入：流操作工具

/**
 * 向导第一步：配置表到类的映射和包选项。
 * 这个类现在通过一个共享的 GeneratorSettings 对象来管理状态。
 */
public class GenerateOptionsDialog extends DialogWrapper { // 类定义：生成选项对话框，继承 DialogWrapper

    private final Project project; // 字段：当前项目实例
    private final GeneratorSettings settings; // 字段：用于在向导步骤间共享数据的设置对象

    // UI 组件声明
    private JTextField modulePathField; // 组件：模块路径文本框
    private JTextField basePackageField; // 组件：基础包路径文本框
    private JTextField entityPackageField; // 组件：实体类包文本框
    private JTextField queryPackageField; // 组件：查询类包文本框
    private JTextField extraClassPrefixField; // 组件：额外类前缀文本框
    private JTextField extraClassSuffixField; // 组件：额外类后缀文本框
    private JTextField ignoreFieldPrefixField; // 组件：忽略字段前缀文本框
    private JTextField ignoreFieldSuffixField; // 组件：忽略字段后缀文本框
    private JTextField ignoreTablePrefixField; // 组件：忽略表前缀文本框
    private JTextField ignoreTableSuffixField; // 组件：忽略表后缀文本框
    private JComboBox<String> encodingCombo; // 组件：编码下拉选择框
    private JTextField superClassField; // 组件：父类文本框

    private JTextField responseWrapperClassField; // 重命名，保持一致
    private JTextField successMethodField;        // 成功标识输入框
    private JTextField failureMethodField;        // 失败标识输入框
    private JRadioButton camelRadio; // 组件：驼峰策略单选按钮
    private JRadioButton sameAsTableNameRadio; // 组件：与表名相同策略单选按钮
    private ButtonGroup strategyGroup; // 组件：策略单选按钮组
    private JTable tableClassMappingTable; // 组件：表名/类名映射表格
    private DefaultTableModel tableModel; // 组件：表格模型

    /**
     * 构造函数，接收共享的 GeneratorSettings 对象。
     * @param project 当前项目实例。
     * @param settings 用于在向导步骤间传递数据的共享设置对象。
     */
    public GenerateOptionsDialog(@NotNull Project project, GeneratorSettings settings) { // 方法签名：构造函数
        super(project, true); // 调用：父类构造函数，模态对话框
        this.project = project; // 赋值：项目字段
        this.settings = settings; // 赋值：保存共享设置对象的引用
        setTitle("生成选项 - 第一步"); // 设置：对话框标题
        init(); // 调用：初始化对话框（包括设置按钮文本）
    }

    /**
     * 重写 init 方法，在其中加载设置。
     * 同时将默认的 "OK" 按钮文本改为 "下一步"。
     */
    @Override // 注解
    protected void init() { // 初始化方法
        super.init(); // 调用父类
        setOKButtonText("下一步"); // 设置按钮文本
        loadSettings(); // 加载设置
    }

    // 【已删除】这里已将被重写的 show() 方法删除，以解决 NullPointerException 问题

    /**
     * 创建中心面板：使用 BorderLayout 包含主面板。
     */
    @Override // 注解：覆盖父类方法
    protected @Nullable JComponent createCenterPanel() { // 方法签名：创建中心面板方法
        JPanel panel = new JPanel(new BorderLayout()); // 创建：BorderLayout 面板
        panel.add(createMainPanel(), BorderLayout.CENTER); // 添加：主面板到中心
        return panel; // 返回：中心面板
    }

    /**
     * 创建主面板：使用 GridBagLayout 布局。
     */
    private JComponent createMainPanel() { // 方法签名：创建主面板方法
        JPanel mainPanel = new JPanel(new GridBagLayout()); // 创建：GridBagLayout 主面板
        GridBagConstraints gbc = new GridBagConstraints(); // 创建：布局约束对象
        gbc.insets = new Insets(5, 5, 5, 5); // 设置：组件间距
        gbc.anchor = GridBagConstraints.WEST; // 设置：左对齐
        gbc.fill = GridBagConstraints.HORIZONTAL; // 设置：水平填充

        int row = 0; // 初始化：行索引

        // --- 第一行：模块路径 + 浏览按钮 + 编码 + 父类 ---
        gbc.gridx = 0; gbc.gridy = row; // 设置：网格位置
        mainPanel.add(new JLabel("模块路径:"), gbc); // 添加：标签
        gbc.gridx = 1; gbc.weightx = 1.0; // 设置：网格位置和权重
        modulePathField = new JTextField("", 25); // 创建：文本框
        mainPanel.add(modulePathField, gbc); // 添加：文本框
        gbc.weightx = 0; // 重置：权重
        gbc.gridx = 2; gbc.fill = GridBagConstraints.NONE; // 设置：网格位置和填充
        JButton browseModulePathButton = new JButton("..."); // 创建：按钮
        browseModulePathButton.addActionListener(e -> chooseModulePath()); // 添加：事件监听
        mainPanel.add(browseModulePathButton, gbc); // 添加：按钮
        gbc.fill = GridBagConstraints.HORIZONTAL; // 恢复：填充
        gbc.gridx = 3; // 设置：网格位置
        mainPanel.add(new JLabel("编码:"), gbc); // 添加：标签
        gbc.gridx = 4; // 设置：网格位置
        encodingCombo = new JComboBox<>(new String[]{"UTF-8", "GBK", "ISO-8859-1"}); // 创建：下拉框
        encodingCombo.setSelectedItem("UTF-8"); // 设置：默认选项
        mainPanel.add(encodingCombo, gbc); // 添加：下拉框
        gbc.gridx = 5; // 设置：网格位置
        mainPanel.add(new JLabel("父类:"), gbc); // 添加：标签
        gbc.gridx = 6; // 设置：网格位置
        superClassField = new JTextField("", 15); // 创建：文本框
        mainPanel.add(superClassField, gbc); // 添加：文本框
        row++; // 行索引递增

        // --- 第二行：基础包路径 + 忽略字段前缀 + 忽略表前缀 ---
        gbc.gridx = 0; gbc.gridy = row; // 设置：网格位置
        mainPanel.add(new JLabel("基础包路径:"), gbc); // 添加：标签
        gbc.gridx = 1; gbc.gridwidth = 2; // 设置：网格位置和跨度
        basePackageField = new JTextField("", 25); // 创建：文本框
        mainPanel.add(basePackageField, gbc); // 添加：文本框
        gbc.gridwidth = 1; // 重置：跨度
        gbc.gridx = 3; // 设置：网格位置
        mainPanel.add(new JLabel("忽略字段前缀:"), gbc); // 添加：标签
        gbc.gridx = 4; // 设置：网格位置
        ignoreFieldPrefixField = new JTextField("", 10); // 创建：文本框
        mainPanel.add(ignoreFieldPrefixField, gbc); // 添加：文本框
        gbc.gridx = 5; // 设置：网格位置
        mainPanel.add(new JLabel("忽略表前缀:"), gbc); // 添加：标签
        gbc.gridx = 6; // 设置：网格位置
        ignoreTablePrefixField = new JTextField("", 10); // 创建：文本框
        mainPanel.add(ignoreTablePrefixField, gbc); // 添加：文本框
        row++; // 行索引递增

        // --- 第三行：实体类包 + 忽略字段后缀 + 忽略表后缀 ---
        gbc.gridx = 0; gbc.gridy = row; // 设置：网格位置
        mainPanel.add(new JLabel("实体类包:"), gbc); // 添加：标签
        gbc.gridx = 1; gbc.gridwidth = 2; // 设置：网格位置和跨度
        entityPackageField = new JTextField("", 25); // 创建：文本框
        mainPanel.add(entityPackageField, gbc); // 添加：文本框
        gbc.gridwidth = 1; // 重置：跨度
        gbc.gridx = 3; // 设置：网格位置
        mainPanel.add(new JLabel("忽略字段后缀:"), gbc); // 添加：标签
        gbc.gridx = 4; // 设置：网格位置
        ignoreFieldSuffixField = new JTextField("", 10); // 创建：文本框
        mainPanel.add(ignoreFieldSuffixField, gbc); // 添加：文本框
        gbc.gridx = 5; // 设置：网格位置
        mainPanel.add(new JLabel("忽略表后缀:"), gbc); // 添加：标签
        gbc.gridx = 6; // 设置：网格位置
        ignoreTableSuffixField = new JTextField("", 10); // 创建：文本框
        mainPanel.add(ignoreTableSuffixField, gbc); // 添加：文本框
        row++; // 行索引递增

        // --- 第四行：查询类包 + 额外类前缀 + 额外类后缀 ---
        gbc.gridx = 0; gbc.gridy = row; // 设置：网格位置
        mainPanel.add(new JLabel("查询类包:"), gbc); // 添加：标签
        gbc.gridx = 1; gbc.gridwidth = 2; // 设置：网格位置和跨度
        queryPackageField = new JTextField("", 25); // 创建：文本框
        mainPanel.add(queryPackageField, gbc); // 添加：文本框
        gbc.gridwidth = 1; // 重置：跨度
        gbc.gridx = 3; // 设置：网格位置
        mainPanel.add(new JLabel("额外类前缀:"), gbc); // 添加：标签
        gbc.gridx = 4; // 设置：网格位置
        extraClassPrefixField = new JTextField("", 10); // 创建：文本框
        mainPanel.add(extraClassPrefixField, gbc); // 添加：文本框
        gbc.gridx = 5; // 设置：网格位置
        mainPanel.add(new JLabel("额外类后缀:"), gbc); // 添加：标签
        gbc.gridx = 6; // 设置：网格位置
        extraClassSuffixField = new JTextField("", 10); // 创建：文本框
        mainPanel.add(extraClassSuffixField, gbc); // 添加：文本框
        row++; // 行索引递增
        // --- 第五行：返回值包装配置 (位于类名策略之前) ---
        gbc.gridx = 0; gbc.gridy = row;
        mainPanel.add(new JLabel("返回值包装类:"), gbc);
        gbc.gridx = 1; gbc.weightx = 0.33; // 分配权重，让文本框可以伸展
        responseWrapperClassField = new JTextField("", 20);
        mainPanel.add(responseWrapperClassField, gbc);

        gbc.gridx = 2; gbc.weightx = 0; // 重置权重
        mainPanel.add(new JLabel("成功标识:"), gbc);
        gbc.gridx = 3; gbc.weightx = 0.33;
        successMethodField = new JTextField("", 10);
        mainPanel.add(successMethodField, gbc);

        gbc.gridx = 4; gbc.weightx = 0;
        mainPanel.add(new JLabel("失败标识:"), gbc);
        gbc.gridx = 5; gbc.weightx = 0.33;
        failureMethodField = new JTextField("", 10);
        mainPanel.add(failureMethodField, gbc);
        gbc.weightx = 0; // 重置权重
        row++; // 行索引递增
        // --- 第六行：类名策略 ---
        gbc.gridx = 0; gbc.gridy = row; // 设置：网格位置
        mainPanel.add(new JLabel("类名策略:"), gbc); // 添加：标签
        gbc.gridx = 1; gbc.gridwidth = 6; // 设置：网格位置和跨度
        JPanel strategyPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); // 创建：一个流式布局的子面板
        camelRadio = new JRadioButton("驼峰"); // 创建：单选按钮
        camelRadio.setSelected(true); // 设置：默认选中
        sameAsTableNameRadio = new JRadioButton("与表名相同"); // 创建：单选按钮
        strategyGroup = new ButtonGroup(); // 创建：按钮组
        strategyGroup.add(camelRadio); // 添加：按钮到组
        strategyGroup.add(sameAsTableNameRadio); // 添加：按钮到组
        strategyPanel.add(camelRadio); // 添加：按钮到子面板
        strategyPanel.add(Box.createHorizontalStrut(10)); // 添加：水平间距
        strategyPanel.add(sameAsTableNameRadio); // 添加：按钮到子面板
        mainPanel.add(strategyPanel, gbc); // 添加：子面板到主面板
        gbc.gridwidth = 1; // 重置：跨度
        row++; // 行索引递增

        // --- 第六行：表名/类名表格 ---
        gbc.gridx = 0; gbc.gridy = row; gbc.gridwidth = 7; // 设置：网格位置和跨度
        gbc.fill = GridBagConstraints.BOTH; // 设置：填充方式
        gbc.weightx = 1.0; gbc.weighty = 1.0; // 设置：拉伸权重
        JComponent tablePanel = createTablePanel(); // 创建：表格面板
        mainPanel.add(tablePanel, gbc); // 添加：表格面板

        addListeners(); // 调用：添加所有事件监听器

        return mainPanel; // 返回：构建完成的主面板
    }

    /**
     * 打开目录选择器以选择模块路径。
     */
    private void chooseModulePath() { // 方法签名：选择模块路径
        FileChooserDescriptor descriptor = new FileChooserDescriptor(false, true, false, false, false, false); // 创建：文件选择器描述符
        descriptor.setTitle("选择模块路径"); // 设置：选择器标题
        descriptor.setDescription("请选择项目的 'src/main' 或 'src/test' 目录"); // 设置：选择器描述
        VirtualFile projectBaseDir = LocalFileSystem.getInstance().findFileByPath(Objects.requireNonNull(project.getBasePath())); // 获取：项目根目录
        VirtualFile[] files = FileChooser.chooseFiles(descriptor, project, projectBaseDir); // 显示：文件选择器
        if (files.length > 0) { // 判断：用户是否选择了文件
            modulePathField.setText(files[0].getPath()); // 设置：文本框内容
        }
    }

    /**
     * 集中添加所有UI组件的监听器。
     */
    private void addListeners() { // 方法签名：添加监听器
        DocumentListener updateListener = new DocumentListener() { // 创建：一个通用的文档监听器
            @Override public void insertUpdate(DocumentEvent e) { updateClassNames(); }
            @Override public void removeUpdate(DocumentEvent e) { updateClassNames(); }
            @Override public void changedUpdate(DocumentEvent e) { updateClassNames(); }
        };

        // 为需要实时回显的字段添加监听器
        ignoreTablePrefixField.getDocument().addDocumentListener(updateListener);
        ignoreTableSuffixField.getDocument().addDocumentListener(updateListener);
        extraClassPrefixField.getDocument().addDocumentListener(updateListener);
        extraClassSuffixField.getDocument().addDocumentListener(updateListener);
        camelRadio.addActionListener(e -> updateClassNames());
        sameAsTableNameRadio.addActionListener(e -> updateClassNames());
    }

    /**
     * 创建表格面板：使用 JTable 展示表名和类名的映射关系。
     */
    private JComponent createTablePanel() { // 方法签名：创建表格面板
        String[] columnNames = {"表名", "类名"}; // 定义：列标题
        tableModel = new DefaultTableModel(columnNames, 0) { // 创建：表格模型
            @Override
            public boolean isCellEditable(int row, int column) { // 重写方法
                return false; // 设置：所有单元格不可编辑
            }
        };
        tableClassMappingTable = new JTable(tableModel); // 创建：表格
        tableClassMappingTable.setFillsViewportHeight(true); // 设置：表格填充整个视口高度
        JScrollPane scrollPane = new JScrollPane(tableClassMappingTable); // 创建：滚动面板
        scrollPane.setPreferredSize(new Dimension(450, 150)); // 设置：首选大小
        return scrollPane; // 返回：滚动面板
    }

    /**
     * 更新类名：从共享的 `settings` 对象获取表名。
     */
    private void updateClassNames() { // 方法签名：更新类名
        if (tableModel == null) return; // 防御：如果表格模型还未初始化，则直接返回
        tableModel.setRowCount(0); // 清空：表格所有行
        if (settings == null || settings.getTableNames() == null) return; // 防御：确保 settings 和其中的表名列表都存在
        for (String tableName : settings.getTableNames()) { // 循环：遍历共享设置中的表名
            String className = generateClassNameFromTable(tableName); // 生成：对应的类名
            tableModel.addRow(new Object[]{tableName, className}); // 添加：新行到表格
        }
    }

    /**
     * 根据当前配置从表名生成最终的类名。
     */
    private String generateClassNameFromTable(String originalTableName) { // 方法签名：从表名生成类名
        String processedName = originalTableName; // 初始化：处理中的名称

        // 处理忽略表前缀
        String ignorePrefixText = ignoreTablePrefixField.getText().trim(); // 获取：忽略前缀文本
        if (!ignorePrefixText.isEmpty()) { // 判断：文本非空
            List<String> ignorePrefixes = Arrays.stream(ignorePrefixText.split(",")) // 分割
                    .map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList()); // 清理并收集
            for (String prefix : ignorePrefixes) { // 循环
                if (processedName.startsWith(prefix)) { // 判断
                    processedName = processedName.substring(prefix.length()); // 移除
                    break; // 跳出
                }
            }
        }

        // 处理忽略表后缀
        String ignoreSuffixText = ignoreTableSuffixField.getText().trim(); // 获取：忽略后缀文本
        if (!ignoreSuffixText.isEmpty()) { // 判断：文本非空
            List<String> ignoreSuffixes = Arrays.stream(ignoreSuffixText.split(",")) // 分割
                    .map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList()); // 清理并收集
            for (String suffix : ignoreSuffixes) { // 循环
                if (processedName.endsWith(suffix)) { // 判断
                    processedName = processedName.substring(0, processedName.length() - suffix.length()); // 移除
                    break; // 跳出
                }
            }
        }

        String baseClassName; // 声明：基础类名
        if (camelRadio.isSelected()) { // 判断
            baseClassName = toCamelCase(processedName); // 转换
        } else {
            baseClassName = processedName; // 保持
        }
        String extraPrefix = extraClassPrefixField.getText().trim(); // 获取：额外前缀
        String extraSuffix = extraClassSuffixField.getText().trim(); // 获取：额外后缀
        return extraPrefix + baseClassName + extraSuffix; // 返回：拼接后的最终类名
    }

    /**
     * 简单下划线转驼峰：用于类名生成。
     */
    private String toCamelCase(String tableName) { // 方法签名：转为驼峰命名
        if (tableName == null || tableName.isEmpty()) return ""; // 防御
        String[] parts = tableName.toLowerCase().split("_"); // 分割
        StringBuilder camel = new StringBuilder(); // 创建
        for (String part : parts) { // 循环
            if (part != null && !part.isEmpty()) { // 判断
                camel.append(Character.toUpperCase(part.charAt(0))).append(part.substring(1)); // 转换
            }
        }
        return camel.toString(); // 返回
    }

    /**
     * 自定义南面板：添加 "上一步"（禁用）、"下一步"、"取消" 按钮。
     */
    @Override // 注解：覆盖父类方法
    protected JComponent createSouthPanel() { // 方法签名：创建南部面板
        JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); // 创建：一个右对齐的流式布局面板
        JButton previousButton = new JButton("上一步"); // 创建：“上一步”按钮
        JButton nextButton = new JButton("下一步"); // 创建：“下一步”按钮
        JButton cancelButton = new JButton("取消"); // 创建：“取消”按钮

        previousButton.setEnabled(false); // 设置：“上一步”按钮禁用

        // 绑定动作到按钮
        nextButton.addActionListener(getOKAction()); // 绑定：“下一步”按钮触发 doOKAction()
        cancelButton.addActionListener(getCancelAction()); // 绑定：“取消”按钮触发 doCancelAction()

        southPanel.add(previousButton); // 添加：按钮到面板
        southPanel.add(Box.createHorizontalStrut(10)); // 添加：水平间距
        southPanel.add(nextButton); // 添加：按钮到面板
        southPanel.add(Box.createHorizontalStrut(10)); // 添加：水平间距
        southPanel.add(cancelButton); // 添加：按钮到面板
        return southPanel; // 返回：创建好的南部面板
    }

    /**
     * 重写 doOKAction 以执行验证并保存设置。
     */
    @Override // 注解：覆盖父类方法
    protected void doOKAction() { // 方法签名：执行OK动作
        // 1. 验证输入
        if (modulePathField.getText().trim().isEmpty()) { // 判断
            Messages.showErrorDialog(project, "模块路径不能为空。", "验证失败"); // 显示
            return; // 中断
        }
        if (tableModel.getRowCount() == 0) { // 判断
            Messages.showErrorDialog(project, "没有要生成的类。", "验证失败"); // 显示
            return; // 中断
        }

        // 2. 保存设置
        saveSettings(); // 调用

        // 3. 关闭对话框并通知主流程继续
        super.doOKAction();
    }

    /**
     * 从共享的 settings 对象中加载数据来填充UI字段。
     */
    private void loadSettings() { // 方法签名：加载设置
        modulePathField.setText(settings.getModulePath()); // 加载：模块路径
        basePackageField.setText(settings.getBasePackage()); // 加载：基础包
        entityPackageField.setText(settings.getEntityPackage()); // 加载：实体类包
        queryPackageField.setText(settings.getQueryPackage()); // 加载：查询类包
        superClassField.setText(settings.getSuperClass()); // 加载父类设置
        responseWrapperClassField.setText(settings.getResponseWrapperClass());
        successMethodField.setText(settings.getSuccessMethodName()); // 加载成功标识
        failureMethodField.setText(settings.getFailureMethodName()); // 加载失败标识
        updateClassNames(); // 调用：更新表格显示
    }

    /**
     * 将此对话框中所有UI字段的数据保存到共享的 settings 对象中。
     */
    private void saveSettings() { // 方法签名：保存设置
        settings.setModulePath(modulePathField.getText()); // 保存：模块路径
        settings.setBasePackage(basePackageField.getText()); // 保存：基础包
        settings.setEntityPackage(entityPackageField.getText()); // 保存：实体类包
        settings.setQueryPackage(queryPackageField.getText()); // 保存：查询类包
        settings.setClassNames(getClassNames()); // 保存：生成的类名列表
        settings.setSuperClass(superClassField.getText()); // 保存父类设置
        //保存忽略字段前后缀的设置
        settings.setIgnoreFieldPrefix(ignoreFieldPrefixField.getText());
        settings.setIgnoreFieldSuffix(ignoreFieldSuffixField.getText());
        settings.setResponseWrapperClass(responseWrapperClassField.getText());
        settings.setSuccessMethodName(successMethodField.getText()); // 保存成功标识
        settings.setFailureMethodName(failureMethodField.getText()); // 保存失败标识
    }

    // --- Getter 方法 ---
    public List<String> getClassNames() { // 获取：类名列表
        List<String> classNames = new ArrayList<>(); // 创建
        for (int i = 0; i < tableModel.getRowCount(); i++) { // 循环
            classNames.add((String) tableModel.getValueAt(i, 1)); // 添加
        }
        return classNames; // 返回
    }
}